package cn.com.uthink.util;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import java.io.*;
import java.net.URLConnection;
import java.util.zip.*;

public final class IOUtilities {

	private static final int TRANSFER_BUFFER = 32768;

	private IOUtilities() {
	}

	public static InputStream getInputStream(URLConnection c) throws IOException {
		InputStream is = c.getInputStream();
		String enc = c.getContentEncoding();
		if ("gzip".equalsIgnoreCase(enc) || "x-gzip".equalsIgnoreCase(enc)) {
			is = new GZIPInputStream(is, TRANSFER_BUFFER);
		} else if ("deflate".equalsIgnoreCase(enc)) {
			is = new InflaterInputStream(is, new Inflater(), TRANSFER_BUFFER);
		}
		return new BufferedInputStream(is);
	}

	public static void transfer(File f, URLConnection c, TransferCallback cb) throws Exception {
		InputStream in = null;
		OutputStream out = null;
		try {
			in = new BufferedInputStream(new FileInputStream(f));
			out = new BufferedOutputStream(c.getOutputStream());
			transfer(in, out, cb);
		} finally {
			close(in);
			close(out);
		}
	}

	public static void transfer(URLConnection c, File f, TransferCallback cb) throws Exception {
		InputStream in = null;
		try {
			in = getInputStream(c);
			transfer(in, f, cb);
		} finally {
			close(in);
		}
	}

	public static void transfer(InputStream s, File f, TransferCallback cb) throws Exception {
		OutputStream out = null;
		try {
			out = new BufferedOutputStream(new FileOutputStream(f));
			transfer(s, out, cb);
		} finally {
			close(out);
		}
	}

	public static void transfer(InputStream in, OutputStream out, TransferCallback cb) throws IOException {
		byte[] bytes = new byte[TRANSFER_BUFFER];
		int count;
		while ((count = in.read(bytes)) != -1) {
			out.write(bytes, 0, count);
			if (cb != null) {
				cb.bytesTransferred(bytes, count);
				if (cb.isCancelled()) {
					break;
				}
			}
		}
	}

	public static void transfer(InputStream in, byte[] bytes) throws IOException {
		int offset = 0;
		int numRead;
		while (offset < bytes.length && (numRead = in.read(bytes, offset, bytes.length - offset)) >= 0) {
			offset += numRead;
		}
		if (offset < bytes.length) {
			throw new IOException("Retry:  Not all bytes were transferred correctly.");
		}
	}

	public static void transfer(InputStream in, OutputStream out) throws IOException {
		byte[] bytes = new byte[TRANSFER_BUFFER];
		int count;
		while ((count = in.read(bytes)) != -1) {
			out.write(bytes, 0, count);
		}
	}

	public static void transfer(File file, OutputStream out) throws IOException {
		InputStream in = null;
		try {
			in = new BufferedInputStream(new FileInputStream(file), TRANSFER_BUFFER);
			transfer(in, out);
		} finally {
			flush(out);
			close(in);
		}
	}

	public static void close(XMLStreamReader reader) {
		try {
			if (reader != null) {
				reader.close();
			}
		} catch (XMLStreamException ignore) {
		}
	}

	public static void close(XMLStreamWriter writer) {
		try {
			if (writer != null) {
				writer.close();
			}
		} catch (XMLStreamException ignore) {
		}
	}

	public static void close(Closeable c) {
		try {
			if (c != null) {
				c.close();
			}
		} catch (IOException ignore) {
		}
	}

	public static void close(InputStream c) {
		try {
			if (c != null) {
				c.close();
			}
		} catch (IOException ignore) {
		}
	}

	public static void close(OutputStream c) {
		try {
			if (c != null) {
				c.close();
			}
		} catch (IOException ignore) {
		}
	}

	public static void flush(Flushable f) {
		try {
			if (f != null) {
				f.flush();
			}
		} catch (IOException ignore) {
		}
	}

	public static void flush(XMLStreamWriter writer) {
		try {
			if (writer != null) {
				writer.flush();
			}
		} catch (XMLStreamException ignore) {
		}
	}

	public static byte[] inputStreamToBytes(InputStream in) {
		try {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			transfer(in, out);
			return out.toByteArray();
		} catch (Exception e) {
			return null;
		}
	}

	public static void transfer(URLConnection c, byte[] bytes) throws IOException {
		OutputStream out = null;
		try {
			out = new BufferedOutputStream(c.getOutputStream());
			out.write(bytes);
		} finally {
			close(out);
		}
	}

	public static void writeToFile(String file, byte[] response) {
		if (response == null) {
			return;
		}
		FileOutputStream fi = null;
		try {
			fi = new FileOutputStream(new File(file));
			fi.write(response);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		close(fi);
	}

	public static void compressBytes(ByteArrayOutputStream original, ByteArrayOutputStream compressed) throws IOException {
		DeflaterOutputStream gzipStream = new GZIPOutputStream(compressed, 32768);
		original.writeTo(gzipStream);
		gzipStream.flush();
		gzipStream.close();
	}

	public interface TransferCallback {
		void bytesTransferred(byte[] bytes, int count);

		boolean isCancelled();
	}
}
